package com.py.framework.core.http;

import java.io.File;
import java.net.URL;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.util.PublicSuffixMatcher;
import org.apache.http.conn.util.PublicSuffixMatcherLoader;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import com.py.framework.core.filter.SecurityCheckFilter;
import com.py.framework.core.log.ExceptionLogger;

/**
 * Http璇锋眰杈呭姪绫�
 * 
 * @author Leegern
 * @date 2018骞�1鏈�11鏃�
 */
public class HttpAgent {

	public static final String DEFAULT_CODE = "UTF-8";

	private static int maxPerRoute = 1500; // 姣忎釜涓绘満鐨勫苟鍙戞渶澶氬彧鏈�1500

	private static int maxTotal = 3000;

	private static HttpAgent instance;

	private PoolingHttpClientConnectionManager cm = null;

	private RequestConfig requestConfig = null;

	private HttpAgent() {
		LayeredConnectionSocketFactory sslsf = null;
		try {
			sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault());
		} catch (NoSuchAlgorithmException e) {
			ExceptionLogger.error(e);
		}
		Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
				.register("https", sslsf).register("http", new PlainConnectionSocketFactory()).build();
		cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
		cm.setMaxTotal(maxTotal);
		cm.setDefaultMaxPerRoute(maxPerRoute);

		requestConfig = RequestConfig.custom().setSocketTimeout(10000000).setConnectTimeout(10000000)
				.setConnectionRequestTimeout(10000000).build();
	}

	/**
	 * 鑾峰彇瀹炰緥
	 * 
	 * @return
	 */
	public static synchronized HttpAgent getInstance() {
		if (null == instance) {
			instance = new HttpAgent();
		}
		return instance;
	}

	/**
	 * 鑾峰彇httpClient瀹炰緥
	 * 
	 * @return
	 */
	public CloseableHttpClient getHttpClient() {
		CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm)
				.setDefaultRequestConfig(requestConfig).build();
		return httpClient;
	}

	/**
	 * 鍙戦�� post璇锋眰
	 * 
	 * @param httpUrl
	 *            鍦板潃
	 * @param jdToken
	 *            鐢ㄦ埛鍙ｄ护
	 */
	public String sendHttpPost(String httpUrl, String jdToken) {
		HttpPost httpPost = new HttpPost(httpUrl); // 鍒涘缓httpPost
		this.setHeader(httpPost, jdToken);
		return sendHttpPost(httpPost);
	}

	/**
	 * 鍙戦�� post璇锋眰
	 * 
	 * @param httpUrl
	 *            鍦板潃
	 * @param jdToken
	 *            鐢ㄦ埛鍙ｄ护
	 * @param params
	 *            鍙傛暟(鏍煎紡:key1=value1&key2=value2)
	 */
	public String sendHttpPost(String httpUrl, String params, String jdToken) {
		HttpPost httpPost = new HttpPost(httpUrl); // 鍒涘缓httpPost
		try {
			this.setHeader(httpPost, jdToken);
			// 璁剧疆鍙傛暟
			StringEntity stringEntity = new StringEntity(params, DEFAULT_CODE);
			stringEntity.setContentType("application/x-www-form-urlencoded");
			httpPost.setEntity(stringEntity);
		} catch (Exception e) {
			ExceptionLogger.error(e);
		}
		return sendHttpPost(httpPost);
	}

	/**
	 * 鍙戦�� post璇锋眰
	 * 
	 * @param httpUrl
	 *            鍦板潃
	 * @param headers
	 *            璇锋眰澶翠俊鎭�
	 * @param params
	 *            鍙傛暟(鏍煎紡:key1=value1&key2=value2)
	 */
	public String sendHttpPost(String httpUrl, String params, Map<String, String> headers) {
		// 鍒涘缓httpPost
		HttpPost httpPost = new HttpPost(httpUrl);
		if (null != headers && headers.size() > 0) {
			// 璁剧疆璇锋眰澶�
			BasicHeader[] bhs = new BasicHeader[headers.size()];
			BasicHeader header = null;
			int index = 0;
			for (Map.Entry<String, String> entry : headers.entrySet()) {
				header = new BasicHeader(entry.getKey(), entry.getValue());
				bhs[index] = header;
				index++;
			}
			httpPost.setHeaders(bhs);
		}
		if (StringUtils.isNotBlank(params)) {
			// 璁剧疆鍙傛暟
			StringEntity stringEntity = new StringEntity(params, DEFAULT_CODE);
			stringEntity.setContentType(headers.get("Content-Type") == null ? "application/x-www-form-urlencoded"
					: headers.get("Content-Type"));
			httpPost.setEntity(stringEntity);

		}
		return sendHttpPost(httpPost);
	}

	/**
	 * 鍙戦�� post璇锋眰
	 * 
	 * @param httpUrl
	 *            鍦板潃
	 * @param jdToken
	 *            鐢ㄦ埛鍙ｄ护
	 * @param maps
	 *            鍙傛暟
	 */
	public String sendHttpPost(String httpUrl, Map<String, String> maps, String jdToken) {
		HttpPost httpPost = new HttpPost(httpUrl); // 鍒涘缓httpPost
		this.setHeader(httpPost, jdToken);
		// 鍒涘缓鍙傛暟闃熷垪
		List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
		for (String key : maps.keySet()) {
			nameValuePairs.add(new BasicNameValuePair(key, maps.get(key)));
		}
		try {
			httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, DEFAULT_CODE));
		} catch (Exception e) {
			ExceptionLogger.error(e);
		}
		return sendHttpPost(httpPost);
	}

	/**
	 * 鍙戦�� post璇锋眰锛堝甫鏂囦欢锛�
	 * 
	 * @param httpUrl
	 *            鍦板潃
	 * @param maps
	 *            鍙傛暟
	 * @param fileLists
	 *            闄勪欢
	 * @param jdToken
	 *            鐢ㄦ埛鍙ｄ护
	 */
	public String sendHttpPost(String httpUrl, Map<String, String> maps, List<File> fileLists, String jdToken) {
		HttpPost httpPost = new HttpPost(httpUrl);// 鍒涘缓httpPost
		MultipartEntityBuilder meBuilder = MultipartEntityBuilder.create();
		this.setHeader(httpPost, jdToken);
		for (String key : maps.keySet()) {
			meBuilder.addPart(key, new StringBody(maps.get(key), ContentType.TEXT_PLAIN));
		}
		for (File file : fileLists) {
			FileBody fileBody = new FileBody(file);
			meBuilder.addPart("files", fileBody);
		}
		HttpEntity reqEntity = meBuilder.build();
		httpPost.setEntity(reqEntity);
		return sendHttpPost(httpPost);
	}

	public String post(String httpUrl, String json) throws Exception {

		HttpPost httpPost = new HttpPost(httpUrl);

		httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");

		StringEntity se = new StringEntity(json);

		httpPost.setEntity(se);

		return sendHttpPost(httpPost);
	}

	/**
	 * 鍙戦�� get璇锋眰
	 * 
	 * @param httpUrl
	 * @param jdToken
	 *            鐢ㄦ埛鍙ｄ护
	 */
	public String sendHttpGet(String httpUrl, String jdToken) {
		HttpGet httpGet = new HttpGet(httpUrl); // 鍒涘缓get璇锋眰
		this.setHeader(httpGet, jdToken);
		return sendHttpGet(httpGet);
	}

	/**
	 * 鍙戦�� get璇锋眰Https
	 * 
	 * @param httpUrl
	 * @param jdToken
	 *            鐢ㄦ埛鍙ｄ护
	 */
	public String sendHttpsGet(String httpUrl, String jdToken) {
		HttpGet httpGet = new HttpGet(httpUrl); // 鍒涘缓get璇锋眰
		this.setHeader(httpGet, jdToken);
		return sendHttpsGet(httpGet);
	}

	/**
	 * 鍙戦�丳ost璇锋眰
	 * 
	 * @param httpPost
	 * @param jdToken
	 *            鐢ㄦ埛鍙ｄ护
	 * @return
	 */
	private String sendHttpPost(HttpPost httpPost) {
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		HttpEntity entity = null;
		String responseContent = "";
		try {
			// 鍒涘缓榛樿鐨刪ttpClient瀹炰緥.
			httpClient = this.getHttpClient();
			httpPost.setConfig(requestConfig);
			// 鎵ц璇锋眰
			response = httpClient.execute(httpPost);
			entity = response.getEntity();
			responseContent = EntityUtils.toString(entity, DEFAULT_CODE);
		} catch (Exception e) {
			ExceptionLogger.error(e);
		}
		return responseContent;
	}

	/**
	 * 鍙戦�丟et璇锋眰
	 * 
	 * @param httpPost
	 * @param jdToken
	 *            鐢ㄦ埛鍙ｄ护
	 * @return
	 */
	private String sendHttpGet(HttpGet httpGet) {
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		HttpEntity entity = null;
		String responseContent = "";
		try {
			// 鍒涘缓榛樿鐨刪ttpClient瀹炰緥.
			httpClient = this.getHttpClient();
			httpGet.setConfig(requestConfig);
			// 鎵ц璇锋眰
			response = httpClient.execute(httpGet);
			entity = response.getEntity();
			responseContent = EntityUtils.toString(entity, DEFAULT_CODE);
		} catch (Exception e) {
			ExceptionLogger.error(e);
		}
		return responseContent;
	}

	/**
	 * 鍙戦�丟et璇锋眰Https
	 * 
	 * @param httpPost
	 * @return
	 */
	private String sendHttpsGet(HttpGet httpGet) {
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		HttpEntity entity = null;
		String responseContent = "";
		try {
			// 鍒涘缓榛樿鐨刪ttpClient瀹炰緥.
			PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader
					.load(new URL(httpGet.getURI().toString()));
			DefaultHostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(publicSuffixMatcher);
			httpClient = HttpClients.custom().setSSLHostnameVerifier(hostnameVerifier).build();
			httpGet.setConfig(requestConfig);
			// 鎵ц璇锋眰
			response = httpClient.execute(httpGet);
			entity = response.getEntity();
			responseContent = EntityUtils.toString(entity, DEFAULT_CODE);
		} catch (Exception e) {
			ExceptionLogger.error(e);
		}
		return responseContent;
	}

	/**
	 * Header璁剧疆Token
	 * 
	 * @param httpGet
	 * @param jdToken
	 */
	private void setHeader(HttpGet httpGet, String jdToken) {
		httpGet.setHeader(SecurityCheckFilter.Token, jdToken);
	}

	/**
	 * Header璁剧疆Token
	 * 
	 * @param httpGet
	 * @param jdToken
	 */
	private void setHeader(HttpPost httpPost, String jdToken) {
		httpPost.setHeader(SecurityCheckFilter.Token, jdToken);
	}
}